﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Data.Linq;
using System.Security.Cryptography;
using System.Collections;

namespace oop_5_server
{
    public partial class CSDB : DataContext
    {
        public Table<Post> Posts;
        public CSDB(string connection) : base(connection) { }
    }

    class ChatServer
    {
        // Instance
        private static ChatServer _instance = null;

        public static ChatServer sharedServer() {
            if (_instance == null)            {
                _instance = new ChatServer();
            }

            return _instance;
        }

        // Service
        WebServer _webServer;

        ArrayList _users;
        CSDB db;
        UserManager _userManager;
        PostManager _postManager;


        private ChatServer()
        {
            _webServer = new WebServer(ChatServer.WSResponse);
            _webServer.Start();

            _users = new ArrayList();

            db = new CSDB(@"Data Source=KEX1K-DESKTOP;Initial Catalog=chat_server;Integrated Security=True;");
            _userManager = new UserManager();
            _postManager = new PostManager(ref _userManager, ref db);


            //_posts = new ArrayList();
        }

        ~ChatServer()
        {
            _webServer.Stop();
        }

        public Packet RequestDispatcher(Dictionary<string, string> query)
        {
            Packet resp = new Packet();

            try
            {
                if (query["entity"].Equals("user"))
                {
                    if (query["action"].Equals("login"))
                    {
                        return _userManager.Login(ref query);
                    }

                    if (query["action"].Equals("get_list"))
                    {
                        return _userManager.GetUserList(ref query);
                    }

                    if (query["action"].Equals("logout"))
                    {
                        return _userManager.Logout(ref query);
                    }

                    if (query["action"].Equals("rename"))
                    {
                        return _userManager.Rename(ref query);
                    }

                }

                if (query["entity"].Equals("post"))
                {
                    if (query["action"].Equals("post"))
                    {
                        var dt = new DateTime(1970, 1, 1, 0, 0, 0, 0);
                        dt = dt.AddSeconds(Convert.ToDouble(query["datetime"]));
                        Post post = new Post
                        {
                            userkey = query["userkey"],
                            username = _userManager.GetUsernameByKey(query["userkey"]),
                            text = query["message"],
                            time = dt
                        };

                        if (query["private"] != "null")
                        {
                            post.@private = query["private"];
                        }
                        
                        resp.Add("entity", "post");
                        
                        if (_postManager.Post(post))
                        {
                            resp.Add("success", "true");
                        }
                        else
                        {
                            resp.Add("success", "false");
                        }

                        return resp;

                    }
                  
                    if (query["action"].Equals("get_list"))
                    {
                        resp.Add("entity", "post");
                        
                        Packet postsResp = _postManager.GetPostsForUser(query["userkey"]);

                        resp.Add("posts", postsResp);

                        if (postsResp.Count > 0)
                        {
                            resp.Add("success", "true");
                        }
                        else
                        {
                            resp.Add("success", "false");
                        }

                        return resp;
                    }

                }
            }
            catch (Exception)
            {
                Console.WriteLine("Misformed request: ");
                foreach (KeyValuePair<string, string> kvp in query)
                {
                    Console.WriteLine("\t\t{0}: {1}; ", kvp.Key, kvp.Value);
                }
                Console.WriteLine();
            }

            return resp;
        }

        public static string WSResponse(HttpListenerRequest request)
        {
            var req = WebServer.GetRequestPostData(request);
            var req_dict = ChatServer.ParseRequest(req);

            Packet resp = ChatServer.sharedServer().RequestDispatcher(req_dict);
            string response = resp.CreateJSON();

            return response;
        }

        static Dictionary<string, string> ParseRequest(string res)
        {
            var lines = res.Split("&".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
            var ht = new Dictionary<string, string>(20);

            for (int i = 0; i < lines.Length; ++i)
            {
                var line = lines[i];
                var pair = line.Split("=".ToCharArray(), 2, StringSplitOptions.RemoveEmptyEntries);

                if (pair.Length == 2)
                {
                    var key = pair[0];
                    var val = pair[1];
                    ht.Add(key, val);
                }
            }

            return ht;
        }
    }
}
